package com.gennlife.dataformat.service;

import com.alibaba.excel.EasyExcel;
import com.gennlife.common.utils.ArrayUtils;
import com.gennlife.common.utils.JavaScriptUtil;
import com.gennlife.common.utils.PropertiesUtil;
import com.gennlife.dataformat.domain.CustodyInfo;
import com.gennlife.dataformat.domain.DiagnosisInfo;
import com.gennlife.dataformat.domain.OperationInfo;
import com.gennlife.dataformat.domain.PageResolveConfig;
import com.gennlife.dataformat.mapper.OperationMapper;
import com.gennlife.framework.domain.TaskInfo;
import com.google.common.collect.Lists;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
public class OperationService {
    private static final Logger logger = LoggerFactory.getLogger(OperationService.class);

    @Autowired
    private OperationMapper mapper;

    public List<OperationInfo> getAll() {
        return mapper.getAll();
    }

    public PageResolveConfig getConfig() {
        return null;
    }

    private static final int TYPE_OF_OPERATION_INFO = 1;

    private static final int TYPE_OF_DIAGNOSIS_INFO = 2;

    private static final int TYPE_OF_CUSTODY_INFO = 3;

    private ArrayList<OperationInfo> operationInfoList = new ArrayList<>();

    private ArrayList<DiagnosisInfo> diagnosisInfoList = new ArrayList<>();

    private ArrayList<CustodyInfo> custodyInfoList = new ArrayList<>();

    public void resolveData(File file) {
        try {
            // 当逐行读写大于2G的文本文件时推荐使用以下代码
            if (!file.isDirectory()) {
                BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
                BufferedReader in = new BufferedReader(new InputStreamReader(bis, "UTF-8"), 10 * 1024 * 1024);// 10M缓存
                String resultFolder = PropertiesUtil.getValue("page.resultFolder");
                String line = "";
                while (in.ready()) {
                    line = in.readLine();
                    if (line.indexOf("\"DOCUMENT_SN\"") == 0) {
                        continue;
                    }
                    resolveLine(line);
                }
                in.close();
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd hh-mm-ss");//设置日期格式
                String date = df.format(new Date());
                //将数据导出到Excel
                int count = 1;
                if (operationInfoList.size() > 1000000) {
                    for (List<OperationInfo> tempOperationInfo : Lists.partition(operationInfoList, 1 + 1000000)) {
                        EasyExcel.write(resultFolder + "/OperationInfo_" + date + "-" + count + "(" + file.getName() + ").xlsx", OperationInfo.class).sheet("Sheet1").doWrite(tempOperationInfo);
                        count++;
                    }
                } else {
                    EasyExcel.write(resultFolder + "/OperationInfo_" + date + "(" + file.getName() + ").xlsx", OperationInfo.class).sheet("Sheet1").doWrite(operationInfoList);
                }
                count = 1;
                if (diagnosisInfoList.size() > 1000000) {
                    for (List<DiagnosisInfo> tempDiagnosisInfo : Lists.partition(diagnosisInfoList, 1000000)) {
                        EasyExcel.write(resultFolder + "/DiagnosisInfo_" + date + "-" + count + "(" + file.getName() + ").xlsx", DiagnosisInfo.class).sheet("Sheet1").doWrite(tempDiagnosisInfo);
                        count++;
                    }
                } else {
                    EasyExcel.write(resultFolder + "/DiagnosisInfo_" + date + "(" + file.getName() + ").xlsx", DiagnosisInfo.class).sheet("Sheet1").doWrite(diagnosisInfoList);
                }
                count = 1;
                if (custodyInfoList.size() > 1000000) {
                    for (List<CustodyInfo> tempCustodyInfo : Lists.partition(custodyInfoList, 1000000)) {
                        EasyExcel.write(resultFolder + "/CustodyInfo_" + date + "-" + count + "(" + file.getName() + ").xlsx", CustodyInfo.class).sheet("Sheet1").doWrite(tempCustodyInfo);
                        count++;
                    }
                } else {
                    EasyExcel.write(resultFolder + "/CustodyInfo_" + date + "(" + file.getName() + ").xlsx", CustodyInfo.class).sheet("Sheet1").doWrite(custodyInfoList);
                }

                //将处理完成的文件移动到备份目录
                operationInfoList.clear();
                diagnosisInfoList.clear();
                custodyInfoList.clear();
                file.renameTo(new File(PropertiesUtil.getValue("page.resolvedFolder") + "/" + file.getName()));
            }
        } catch (IOException ex) {
            logger.error("异常:" + ex.getMessage());
        }
    }

    public String resolveDataTest(String line, String jsCode) throws ScriptException, NoSuchMethodException {
        //获取ScriptEngineManager对象
        ScriptEngineManager manager = new ScriptEngineManager();
        //获取JavaScript执行引擎
        ScriptEngine engine = manager.getEngineByName("js");
        String script = "function resolve(line){" + jsCode + "}";
        engine.eval(script);
        Invocable inv = (Invocable) engine;
        ScriptObjectMirror eval = (ScriptObjectMirror) inv.invokeFunction("resolve", line);
        List<Map<String, String>> listObjectFir = (List<Map<String, String>>) JavaScriptUtil.toObject(eval);
        for (Map<String, String> mapList : listObjectFir) {
            for (Map.Entry entry : mapList.entrySet()) {
                System.out.println(entry.getKey() + "  " + entry.getValue());
            }
        }
        return "OK";
    }

    public String resolveDataAll(TaskInfo info) throws ScriptException {
        //获取ScriptEngineManager对象
        ScriptEngineManager manager = new ScriptEngineManager();
        //获取JavaScript执行引擎
        ScriptEngine engine = manager.getEngineByName("js");
        String script = "function resolve(line){" + info.getTaskResolveCode() + "}";
        engine.eval(script);
        Invocable inv = (Invocable) engine;
        File file = new File(info.getTaskFileDir());
        File resultFolder = new File(info.getTaskFileDir() + "/result");
        if (!resultFolder.exists()) {
            resultFolder.mkdir();
        }
        File resolvedFolder = new File(info.getTaskFileDir() + "/resolved");
        if (!resolvedFolder.exists()) {
            resolvedFolder.mkdir();
        }
        List<List<String>> resultList = new ArrayList<>();
        String[] fs = file.list();
        for (String fileName : fs) {
            try {
                file = new File(info.getTaskFileDir() + "/" + fileName);
                // 当逐行读写大于2G的文本文件时推荐使用以下代码
                if (!file.isDirectory()) {
                    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
                    BufferedReader in = new BufferedReader(new InputStreamReader(bis, "UTF-8"), 10 * 1024 * 1024);// 10M缓存
                    String line = "";
                    while (in.ready()) {
                        line = in.readLine();
                        ScriptObjectMirror mirror = (ScriptObjectMirror) inv.invokeFunction("resolve", line);
                        if (mirror.isEmpty()) {
                            continue;
                        }
                        List<List<String>> listObject = (List<List<String>>) JavaScriptUtil.toObject(mirror);
                        resultList.addAll(listObject);
                    }
                    in.close();
                    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd hh-mm-ss");//设置日期格式
                    String date = df.format(new Date());
                    //将数据导出到Excel
                    int count = 1;
                    if (resultList.size() > 1000000) {
                        for (List temp : Lists.partition(resultList, 1 + 1000000)) {
                            EasyExcel.write(resultFolder + "/" + info.getTaskName() + "_" + date + "-"
                                    + count + "(" + file.getName() + ").xlsx")
                                    .sheet(info.getTaskName()).doWrite(temp);
                            count++;
                        }
                    } else {
                        EasyExcel.write(resultFolder + "/" + info.getTaskName() + "_" +
                                date + "(" + file.getName() + ").xlsx")
                                .sheet(info.getTaskName()).doWrite(resultList);
                    }
                    resultList.clear();
                    file.renameTo(new File(info.getTaskFileDir() + "/resolved/" + file.getName()));
                }
            } catch (IOException | NoSuchMethodException e) {
                logger.error("**********************" + fileName + "文件出现IO错误**********************");
            }
        }
        return "OK";
    }

    private void resolveLine(String line) throws IOException {
        if (line.length() > 0) {
            dealLine(line, "II助", new String[]{"离院方式", "</text>"});
            dealLine(line, "入院    病情", new String[]{"入院病情：1.有，2.临床未确定，3.情况不明，4.无", "损伤、中毒外部原因：", "出 院 诊 断", "用血量："});
            dealLine(line, "出重症监护室时间（年_月_日_时_分）", new String[]{"呼吸机使用时间：", "</text>"});
        }
    }

    public static boolean isContainChinese(String str) {
        Pattern p = Pattern.compile("[\u4e00-\u9fa5]");
        Matcher m = p.matcher(str);
        if (m.find()) {
            return true;
        }
        return false;
    }

    public String[] formatArray(String[] arrays, int len) {
        if (arrays.length > len && arrays.length % len != 0) {
            for (int j = 0; j < arrays.length / len; j++) {
                if (arrays[1 + len * j].length() != len) {
                    arrays[1 + len * j] = arrays[len * j] + "_" + arrays[1 + len * j];
                    arrays = ArrayUtils.delElement(arrays, len * j);
                    arrays = formatArray(arrays, len);
                }
            }
        }
        return arrays;
    }

    private String dealLine(String line, String keyStart, String[] keyEnd) {
        String tempText = "";
        StringBuffer result = new StringBuffer();
        String[] lineParams = line.split("@genn");
        int tempIndex = -1;
        if (lineParams.length > 11) {
            line = lineParams[11];
            for (int keyEndLen = 0; keyEndLen < keyEnd.length; keyEndLen++) {
                try {
                    if (line.indexOf(keyStart) > -1) {
                        line = line.substring(line.indexOf(keyStart) + keyStart.length());
                        tempIndex = line.indexOf(keyEnd[keyEndLen]);
                        if (tempIndex > -1) {
                            tempText = line.substring(0, tempIndex).trim();
                            if (!keyStart.equals("II助")) {
                                tempText = tempText.replaceAll("        ", "    ").replaceAll("        ", "    ")
                                        .replaceAll("        ", "    ").replaceAll("        ", "    ")
                                        .replaceAll("        ", "    ").replaceAll("        ", "    ")
                                        .replaceAll("        ", "    ").replaceAll("        ", "    ")
                                        .replaceAll("     ", "    ").replaceAll("     ", "    ")
                                        .replaceAll("     ", "    ").replaceAll("     ", "    ")
                                        .replaceAll("     ", "    ").replaceAll("     ", "    ");
                            }
                            tempText = tempText.replaceAll("    ", "@genn");
                            if (keyStart.equals("II助")) {
                                String[] infos = tempText.trim().split("@genn");
                                if (infos.length <= 9 && infos.length > 4 && infos[1].length() == 10) {
                                    String[] temp = new String[10];
                                    System.arraycopy(infos, 0, temp, 0, infos.length);
                                    infos = temp;
                                    for (int i = 0; i < 10; i++) {
                                        if (infos[i] == null) {
                                            infos[i] = "/";
                                        }
                                    }
                                }
                                if (infos.length > 9) {
//                                    infos = formatArray(infos, 10);
                                    result.append(simpleDealInfos(TYPE_OF_OPERATION_INFO, infos, 10, lineParams[1], lineParams[3]));
                                }
                            } else if (keyStart.equals("入院    病情")) {
                                String[] infos = tempText.trim().split("@genn");
                                if (infos.length > 2) {
                                    //处理截取的开头可能有问题
                                    for (int i = 0; i < infos.length; i++) {
                                        if (i % 3 == 1) {
                                            if (isContainChinese(infos[i])) {
                                                infos[i - 1] = infos[i - 1] + infos[i];
                                                infos = ArrayUtils.delElement(infos, i);
                                            }
                                            if (infos[i].length() == 1) {
                                                infos = ArrayUtils.addElement(infos, i, "XXX.XXX");
                                            }
                                        }
                                    }
                                    result.append(simpleDealInfos(TYPE_OF_DIAGNOSIS_INFO, infos, 3, lineParams[1], lineParams[3]));
                                }
                            } else if (keyStart.equals("出重症监护室时间（年_月_日_时_分）")) {
                                String[] infos = tempText.trim().split("@genn");
                                if (infos.length > 2) {
                                    //处理截取的开头可能有问题
                                    result.append(simpleDealInfos(TYPE_OF_CUSTODY_INFO, infos, 3, lineParams[1], lineParams[3]));
                                }
                            }

                        }
                    }
                } catch (Exception e) {
                    logger.error("错误数据line:" + line);
                    return "";
                }
            }
        }

        return result.toString();
    }

    private String simpleDealInfos(int type, String[] infos, int cloumnNum, String pSn, String vSn) {
        pSn = pSn.replaceAll("\"", "");
        vSn = vSn.replaceAll("\"", "");
        StringBuffer result = new StringBuffer();
        StringBuffer buffer;
        OperationInfo operationInfo = null;
        DiagnosisInfo diagnosisInfo = null;
        CustodyInfo custodyInfo = null;
        int len = infos.length;

        if (type == TYPE_OF_OPERATION_INFO && len / cloumnNum > 0 && len % cloumnNum > 1) {
            int addLine = cloumnNum - len % cloumnNum;
            infos = Arrays.copyOf(infos, infos.length + addLine);
            for (int i = 0; i < addLine; i++) {
                infos[i + len] = "";
            }
        }
        for (int i = 0; i < infos.length; i++) {
            try {
                if (i % cloumnNum == 0 && (i + cloumnNum) <= infos.length
                        && infos[i + 1].replaceAll("-", "").trim().length() > 0) {
                    buffer = new StringBuffer();
                    int emptyNum = 0;
                    operationInfo = new OperationInfo();
                    diagnosisInfo = new DiagnosisInfo();
                    custodyInfo = new CustodyInfo();
                    for (int j = 0; j < cloumnNum; j++) {
                        if (infos[i + j].equals("-")) {
                            emptyNum++;
                            infos[i + j] = "";
                        }
                        if (type == TYPE_OF_OPERATION_INFO) {
                            operationInfo.setInpatientSn(pSn);
                            operationInfo.setVisitSn(vSn);
                            if (j % cloumnNum == 0) {
                                operationInfo.setOperationCode(infos[i + j]);
                            } else if (j % cloumnNum == 1) {
                                //  "incision_grade"	"anesthesia_mode"	"anesthesia_doctor"
                                operationInfo.setOperationDate(infos[i + j]);
                            } else if (j % cloumnNum == 2) {
                                operationInfo.setOperationLevel(infos[i + j]);
                            } else if (j % cloumnNum == 3) {
                                operationInfo.setOperationName(infos[i + j]);
                            } else if (j % cloumnNum == 4) {
                                operationInfo.setOperationDoctor(infos[i + j]);
                            } else if (j % cloumnNum == 5) {
                                operationInfo.setOperationAssOne(infos[i + j]);
                            } else if (j % cloumnNum == 6) {
                                operationInfo.setOperationAssTwo(infos[i + j]);
                            } else if (j % cloumnNum == 7) {
                                operationInfo.setIncisionGrade(infos[i + j]);
                            } else if (j % cloumnNum == 8) {
                                operationInfo.setAnesthesiaMode(infos[i + j]);
                            } else if (j % cloumnNum == 9) {
                                operationInfo.setAnesthesiaDoctor(infos[i + j]);
                            }
                        } else if (type == TYPE_OF_DIAGNOSIS_INFO) {
                            diagnosisInfo.setInpatientSn(pSn);
                            diagnosisInfo.setVisitSn(vSn);
                            if (j % cloumnNum == 0) {
                                diagnosisInfo.setDiagnosisName(infos[i + j]);
                            } else if (j % cloumnNum == 1) {
                                //  "incision_grade"	"anesthesia_mode"	"anesthesia_doctor"
                                diagnosisInfo.setDiagnosisCode(infos[i + j]);
                            } else if (j % cloumnNum == 2) {
                                diagnosisInfo.setDiagnosisIllness(infos[i + j]);
                            }
                        } else if (type == TYPE_OF_CUSTODY_INFO) {
                            custodyInfo.setInpatientSn(pSn);
                            custodyInfo.setVisitSn(vSn);
                            if (j % cloumnNum == 0) {
                                custodyInfo.setCustodyName(infos[i + j]);
                            } else if (j % cloumnNum == 1) {
                                //  "incision_grade"	"anesthesia_mode"	"anesthesia_doctor"
                                custodyInfo.setCustodyInDate(infos[i + j]);
                            } else if (j % cloumnNum == 2) {
                                custodyInfo.setCustodyOutDate(infos[i + j]);
                            }
                        }
                        buffer.append("\"").append(infos[i + j]).append("\"").append("\t");
                    }
                    if (emptyNum < cloumnNum && !buffer.toString().startsWith("\"\"\t\"XXX.XXX\"\t\"\"")) {
                        if (type == TYPE_OF_OPERATION_INFO && null != operationInfo) {
                            operationInfoList.add(operationInfo);
                        } else if (type == TYPE_OF_DIAGNOSIS_INFO && null != diagnosisInfo) {
                            diagnosisInfoList.add(diagnosisInfo);
                        } else if (type == TYPE_OF_CUSTODY_INFO & null != custodyInfo) {
                            custodyInfoList.add(custodyInfo);
                        }
                        result.append(buffer.append(pSn).append("\t").append(vSn));
                    }
                }
            } catch (Exception e) {
                logger.error("解析错误");
                return "";
            }
        }
        return result.toString();
    }

}
